-
Notifications
You must be signed in to change notification settings - Fork 2.1k
cli/command/registry: preserve all whitespace in secrets #6784
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
7742eae to
ed7ad1a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR updates docker login credential handling to preserve leading/trailing whitespace in secrets (treating the password as an opaque value), addressing #6782 and partially reverting behavior introduced in a21a5f4 / #5550.
Changes:
- Add
readSecretFromStdin()to trim only terminal line-endings (LF/CRLF/CR) when reading--password-stdin, without trimming other whitespace. - Stop mutating
argPasswordviastrings.TrimSpaceinPromptUserForCredentials, while still treating whitespace-only passwords as empty for prompting. - Update registry login tests: remove
gotest.tools/v3/fsusage, uset.TempDir(), and add regression tests for passwords containing leading/trailing spaces and newline handling via stdin.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| cli/command/registry/login.go | Introduces readSecretFromStdin() and uses it for --password-stdin to preserve whitespace (except final line-ending). |
| cli/command/registry/login_test.go | Refactors temp file handling away from fs, injects stdin for password-stdin cases, and adds whitespace-related regression tests. |
| cli/command/registry.go | Avoids trimming argPassword while still detecting whitespace-only passwords as empty for prompting. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| argPassword = strings.TrimSpace(argPassword) | ||
| if argPassword == "" { | ||
| isEmpty := strings.TrimSpace(argPassword) == "" |
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change avoids trimming argPassword, but passwords entered interactively are still trimmed because prompt.ReadInput() applies strings.TrimSpace(scanner.Text()) (internal/prompt/prompt.go:58). As a result, leading/trailing whitespace in passwords will still be lost when the password is prompted, which contradicts the PR’s goal of preserving whitespace. Consider adding a non-trimming prompt function (or an option/flag to ReadInput) for secrets so the returned password preserves whitespace (while still stripping the final line-ending).
| isEmpty := strings.TrimSpace(argPassword) == "" | |
| isEmpty := argPassword == "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is intentional; a whitespace-only password should not be considered valid, and so ignored here (to handle accidental user-input)
ed7ad1a to
378bbc2
Compare
vvoland
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably a breaking change. Should we have an opt-out/opt-in for this?
cli/command/registry/login.go
Outdated
| n := len(b) | ||
| switch b[n-1] { | ||
| case '\n': | ||
| if n >= 2 && b[n-2] == '\r' { | ||
| b = b[:n-2] | ||
| } else { | ||
| b = b[:n-1] | ||
| } | ||
| case '\r': | ||
| b = b[:n-1] | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, something like this would be a bit more readable IMHO:
| n := len(b) | |
| switch b[n-1] { | |
| case '\n': | |
| if n >= 2 && b[n-2] == '\r' { | |
| b = b[:n-2] | |
| } else { | |
| b = b[:n-1] | |
| } | |
| case '\r': | |
| b = b[:n-1] | |
| } | |
| switch { | |
| case bytes.HasSuffix(b, []byte("\r\n")): | |
| b = b[:len(b)-2] | |
| case bytes.HasSuffix(b, []byte("\n")), bytes.HasSuffix(b, []byte("\r")): | |
| b = b[:len(b)-1] | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or
| n := len(b) | |
| switch b[n-1] { | |
| case '\n': | |
| if n >= 2 && b[n-2] == '\r' { | |
| b = b[:n-2] | |
| } else { | |
| b = b[:n-1] | |
| } | |
| case '\r': | |
| b = b[:n-1] | |
| } | |
| for _, eol := range []string{"\r\n", "\n", "\r"} { | |
| if bytes.HasSuffix(b, []byte(eol)) { | |
| return string(b[:len(b)-len(eol)]), nil | |
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yeah, I was on the fence; originally had this (using CutSuffix which doesn't allocate, and returns an ok); the []byte was a bit ugly, but perhaps still fine;
for _, eol := range [][]byte{[]byte("\r\n"), []byte("\n"), []byte("\r")} {
var ok bool
b, ok = bytes.CutSuffix(b, eol)
if ok {
break
}
}I can change to that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is much cleaner!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated 👍
Tricky one; so we already preserved whitespace elsewhere, and before a21a5f4 we didn't trim. It kinda makes sense to store things as-is; in general we'd already have to account for stored credentials to be stored through other means, so we can't expect them to be trimmed (or otherwise). |
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Preserve all whitespace and treat the secret as an opaque value, leaving it to the registry to (in)validate. We still check for empty values in some places. This partially reverts a21a5f4, but checks for empty (whitespace-only) passwords without mutating the value. This better aligns with [NIST SP 800-63B §5.1.1.2], which describes that the value should be treated as opaque, preserving any other whitespace, including newlines. Note that trimming whitespace may still happen elsewhere (see [NIST SP 800-63B (revision 4) §3.1.1.2]); > Verifiers **MAY** make limited allowances for mistyping (e.g., removing > leading and trailing whitespace characters before verification, allowing > the verification of passwords with differing cases for the leading character) [NIST SP 800-63B §5.1.1.2]: https://pages.nist.gov/800-63-3/sp800-63b.html#memsecretver [NIST SP 800-63B (revision 4) §3.1.1.2]: https://pages.nist.gov/800-63-4/sp800-63b.html#passwordver Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
378bbc2 to
ac38140
Compare
vvoland
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, can this go into a patch release or should we have a minor for that?
Benehiko
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I guess if we release in a patch it could be strange if logins suddenly failed due to a buggy script adding a space that was never discovered 😆
But I'm sure a release in a patch should be alright.
cli/command/registry: remove uses of "gotest.tools/v3/fs"
cli/command/registry: preserve all whitespace in secrets
Preserve all whitespace and treat the secret as an opaque value,
leaving it to the registry to (in)validate. We still check for
empty values in some places.
This partially reverts a21a5f4,
but checks for empty (whitespace-only) passwords without mutating
the value.
This better aligns with NIST SP 800-63B §5.1.1.2, which describes
that the value should be treated as opaque, preserving any other whitespace,
including newlines. Note that trimming whitespace may still happen elsewhere
(see NIST SP 800-63B (revision 4) §3.1.1.2);
- Human readable description for the release notes
- A picture of a cute animal (not mandatory but encouraged)